Skip to content

net: add synchronous, role-neutral net.BoundSocket#63951

Closed
guybedford wants to merge 1 commit into
nodejs:mainfrom
guybedford:tcp-bound-handle
Closed

net: add synchronous, role-neutral net.BoundSocket#63951
guybedford wants to merge 1 commit into
nodejs:mainfrom
guybedford:tcp-bound-handle

Conversation

@guybedford

@guybedford guybedford commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Add net.BoundSocket, a synchronous TCP bind primitive that mirrors POSIX bind(2): the socket is bound to a local address but stays role-agnostic until it is adopted as a server (server.listen()) or a client (new net.Socket({ handle }) followed by connect()).

Constructing a net.BoundSocket binds inline via the existing uv_tcp_bind() path, so the kernel-assigned address (including the ephemeral port when port is 0) is available immediately via boundSocket.address(), and bind errors throw synchronously.

Adoption transfers ownership of the underlying handle; afterwards address() and close() throw ERR_SOCKET_HANDLE_ADOPTED. An un-adopted handle is released with close() or via Symbol.dispose (using).

The handle is passed in-process rather than as a file descriptor, so it also works on Windows.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added errors Issues and PRs related to JavaScript errors originated in Node.js core. needs-ci PRs that need a full CI run. net Issues and PRs related to the net subsystem. labels Jun 16, 2026
@guybedford guybedford force-pushed the tcp-bound-handle branch 2 times, most recently from 5db58e1 to 9da4d5f Compare June 17, 2026 00:07
@mcollina

Copy link
Copy Markdown
Member

I don't understand why this is needed

@Ethan-Arrowood Ethan-Arrowood left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate this change. net.BoundHandle lets you reserve a TCP port and actually hold onto it until you're ready to use it. This simplifies utility modules like get-port that are susceptible to TOCTOU (Time-of-Check to Time-of-Use) race conditions. Of course, it doesn't solve the problem perfectly since this is in-process only, but I think it's a great improvement.

As a follow-up, it'd be great if BoundHandle could optionally expose its underlying file descriptor, so the reservation can be handed to another process (Unix-only, since this relies on POSIX fd passing). That would extend the same race-free guarantee across a process boundary.

@guybedford

guybedford commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for clarifying the use case here @Ethan-Arrowood. I've gone ahead and added a commit to expose the fd() as well here for the additional thread-passing use case.

@guybedford guybedford added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Jun 17, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@mcollina

Copy link
Copy Markdown
Member

@guybedford can you update the docs to clarify when somebody would need this?

@mcollina

Copy link
Copy Markdown
Member

is it possible to make this transferable across threads?

@guybedford

Copy link
Copy Markdown
Contributor Author

@mcollina I've gone ahead and simplified the docs to keep the explanation and example simple. Use cases for binding a net.Socket() are generally considered more obscure, but include multi-homed servers that must control egress IP or port, network tools (like ping/traceroute) and legacy privileged port protocols. This offers functional completeness with the posix model, while the major use case for most Node.js users I think will be the synchronous port reservation (either via explicit port or port: 0 auto assignment). IP reservation for multi-IP/virtual IP use cases may be less common there as well.

In terms of the design, I originally called this bindSync since it reflects the full functionality of bind(2), but since it returns a BoundHandle renamed it to be the BoundHandle constructor. If this is confusing, I can certainly rename it back to net.bindSync() or even just net.bind() though certainly. It effectively mirrors the new TCP() in TCP wrap, effectively closing the gap on use cases that would otherwise need to dip into that pseudo-private API.

For threads, I have already extended the API to support boundHandle.fd() for passing, so that the threaded use case can work here (by passing the fd option to listen({ fd }) within the receiving thread). The reason I didn't make BoundHandle itself serializable here is that on Windows we can't support this, so explicitly using fd , we make it clearer this is posix-specific.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Comment thread test/parallel/test-net-boundhandle.js Outdated
@guybedford guybedford changed the title net: add synchronous, role-neutral net.BoundHandle net: add synchronous, role-neutral net.BoundSocket Jun 19, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@guybedford guybedford added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. commit-queue Add this label to land a pull request using GitHub Actions. labels Jun 20, 2026
@nodejs-github-bot nodejs-github-bot added commit-queue-failed An error occurred while landing this pull request using GitHub Actions. and removed commit-queue Add this label to land a pull request using GitHub Actions. labels Jun 20, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator
Commit Queue failed
- Loading data for nodejs/node/pull/63951
✔  Done loading data for nodejs/node/pull/63951
----------------------------------- PR info ------------------------------------
Title      net: add synchronous, role-neutral net.BoundSocket (#63951)
   ⚠  Could not retrieve the email or name of the PR author's from user's GitHub profile!
Branch     guybedford:tcp-bound-handle -> nodejs:main
Labels     net, errors, author ready, needs-ci
Commits    1
 - net: early TCP binding via synchronous net.BoundSocket
Committers 1
 - Guy Bedford <gbedford@cloudflare.com>
PR-URL: https://github.com/nodejs/node/pull/63951
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
------------------------------ Generated metadata ------------------------------
PR-URL: https://github.com/nodejs/node/pull/63951
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
--------------------------------------------------------------------------------
   ℹ  This PR was created on Tue, 16 Jun 2026 23:51:31 GMT
   ✔  Approvals: 3
   ✔  - Ethan Arrowood (@Ethan-Arrowood): https://github.com/nodejs/node/pull/63951#pullrequestreview-4516323660
   ✔  - James M Snell (@jasnell) (TSC): https://github.com/nodejs/node/pull/63951#pullrequestreview-4535764288
   ✔  - Matteo Collina (@mcollina) (TSC): https://github.com/nodejs/node/pull/63951#pullrequestreview-4536589329
   ✘  1 GitHub CI job(s) failed:
   ✘    - aarch64-linux: with shared boringssl-0.20260526.0: FAILURE (https://github.com/nodejs/node/actions/runs/27852741325/job/82463981053)
   ℹ  Last Full PR CI on 2026-06-20T05:30:24Z: https://ci.nodejs.org/job/node-test-pull-request/74283/
- Querying data for job/node-test-pull-request/74283/
✔  Build data downloaded
   ✔  Last Jenkins CI successful
--------------------------------------------------------------------------------
   ✔  Aborted `git node land` session in /home/runner/work/node/node/.ncu
https://github.com/nodejs/node/actions/runs/27863741122

Signed-off-by: Guy Bedford <guybedford@gmail.com>
guybedford added a commit that referenced this pull request Jun 20, 2026
Signed-off-by: Guy Bedford <guybedford@gmail.com>
PR-URL: #63951
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
@guybedford guybedford removed author ready PRs that have at least one approval, no pending requests for changes, and a CI started. commit-queue-failed An error occurred while landing this pull request using GitHub Actions. labels Jun 20, 2026
@guybedford

Copy link
Copy Markdown
Contributor Author

Landed in e3cdb14.

@guybedford guybedford closed this Jun 20, 2026
@guybedford guybedford deleted the tcp-bound-handle branch June 20, 2026 21:41
aduh95 pushed a commit that referenced this pull request Jun 20, 2026
Signed-off-by: Guy Bedford <guybedford@gmail.com>
PR-URL: #63951
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

errors Issues and PRs related to JavaScript errors originated in Node.js core. needs-ci PRs that need a full CI run. net Issues and PRs related to the net subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants